﻿using System;
using System.Collections.Generic;

using System.Linq.Expressions;
using System.Web.Mvc;

namespace eCRAM.WebSite.Tools
{
    public class TableDescription<TModel>
    {
        public TableDescription()
        {
            _rows = new List<TableRowDescription<TModel>>();
        }

        private string _hiddenFieldName;
        public string HiddenFieldName
        {
            get
            {
                if (string.IsNullOrEmpty(_hiddenFieldName))
                {
                    return "SelectedField";
                }
                return _hiddenFieldName;
            }
            set { _hiddenFieldName = value; }
        }

        /// <summary>
        /// Récupére la clé
        /// </summary>
        public Func<TModel, Guid> GetKeyMethod { get; set; }

        /// <summary>
        /// Liste des colonnes
        /// </summary>
        private readonly ICollection<TableRowDescription<TModel>> _rows;
        
        /// <summary>
        /// Liste des colonnes
        /// </summary>
        public IEnumerable<TableRowDescription<TModel>> Rows 
        {
            get { return _rows; } 
        }

        /// <summary>
        /// Détermine si le contenu peut être modifié
        /// </summary>
        public bool IsEditable { get { return !string.IsNullOrEmpty(EditActionName); } }
        /// <summary>
        /// Nom de l'action de modification
        /// </summary>
        public string EditActionName { get; set; }
        /// <summary>
        /// Détermine si le contenu peut être modifié
        /// </summary>
        public bool IsDeletable { get { return !string.IsNullOrEmpty(DeleteActionName); } }
        /// <summary>
        /// Nom de l'action de suppression
        /// </summary>
        public string DeleteActionName { get; set; }

        public void AddRow(TableRowDescription<TModel> row)
        {
            if (row != null)
            {
                row.TableDescription = this;
                _rows.Add(row);
            }
        }
    }

    public class TableRowDescription<TModel>
    {

        public TableRowDescription(string pHeader, Expression<Func<TModel, object>> pGetMethod)
        {
            Header = pHeader;
            GetMethod = pGetMethod;
        }

        public TableDescription<TModel> TableDescription { get; set; }

        /// <summary>
        /// Header de la colonne
        /// </summary>
        public string Header { get; set; }
        /// <summary>
        /// Méthode de récuperation de la colonne
        /// </summary>
        public Expression<Func<TModel, object>> GetMethod { get; set; }
        /// <summary>
        /// Chaine de formattage
        /// </summary>
        public string FormatString { get; set; }

        /// <summary>
        /// Récupére la valeur à afficher
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        protected virtual object GetValue(TModel item)
        {
            return GetMethod.Compile().Invoke(item);
        }


        /// <summary>
        /// Récupére la valuer a afficher corresctement formatée
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="item"></param>
        /// <param name="formName"></param>
        /// <param name="field"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        internal virtual string GetValue(HtmlHelper helper, TModel item, string formName, string field, int index)
        {
            object val = GetValue(item);
            if (val == null)
            {
                return string.Empty;
            }

            if (string.IsNullOrEmpty(FormatString) || !(val is IFormattable))
            {
                return val.ToString();
            }

            return (val as IFormattable).ToString(FormatString, System.Globalization.CultureInfo.CurrentUICulture);
        }
    }

    public class CheckBoxRowDescription<TModel> : TableRowDescription<TModel>
    {
        /// <summary>
        /// Récupére la valeur à afficher
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        protected override object GetValue(TModel item)
        {
            return _getBoolMethod.Compile().Invoke(item);
        }

        public CheckBoxRowDescription(string pHeader, Expression<Func<TModel, bool?>> pGetMethod)
            : base(pHeader, null)
        {
            _getBoolMethod = pGetMethod;
            _propertyName = Helpers.GetPropertyPath(pGetMethod);
        }

        readonly Expression<Func<TModel, bool?>> _getBoolMethod;
        private readonly string _propertyName;

        internal override string GetValue(HtmlHelper helper, TModel item, string formName, string field, int index)
        {
            bool val = GetValue(item) != null && GetValue(item).Equals(true);

            string idField = string.Format("Chk[{0}]_{1}", index, _propertyName);

            string script = string.Format(
                "var form = document.forms['{0}']; form['{3}.{1}'].value = form['{2}'].checked; if(form['{3}.Status'].value == 'None') {{ form['{3}.Status'].value = 'Update';}}",
                formName,
                _propertyName,
                idField, field);


            return string.Format("<input id='{2}' type='checkbox'  onclick=\"{1}\" {0}  />",
                val ? "checked='checked'" : "",
                script,
                idField);


        }
    }


    public class ReadonlyCheckBoxRowDescription<TModel> : TableRowDescription<TModel>
    {
        /// <summary>
        /// Récupére la valeur à afficher
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        protected override object GetValue(TModel item)
        {
            return _getBoolMethod.Compile().Invoke(item);
        }

        public ReadonlyCheckBoxRowDescription(string header, Expression<Func<TModel, bool?>> getMethod)
            : base(header, null)
        {
            _getBoolMethod = getMethod;
        }

        readonly Expression<Func<TModel, bool?>> _getBoolMethod;

        internal override string GetValue(HtmlHelper helper, TModel item, string formName, string field, int index)
        {
            return helper.CheckBoxForNullableBool(_getBoolMethod, item).ToHtmlString();
        }
    }

    public class ActionRowDescription<TModel> : TableRowDescription<TModel>
    {
        public ActionRowDescription(string label, string actionName)
            : base(string.Empty, null)
        {
            _actionName = actionName;
            _label = label;
        }

        private readonly string _actionName;
        private readonly string _label;

        internal override string GetValue(HtmlHelper helper, TModel item, string formName, string field, int index)
        {
            string additionalScript = string.Format("form['{0}'].value = '{1}';", TableDescription.HiddenFieldName, TableDescription.GetKeyMethod.Invoke(item));
            return helper.HyperLink(_actionName, _label, formName, additionalScript).ToHtmlString();
        }
    }

    public class ConditionnalActionRowDescription<TModel> : ActionRowDescription<TModel>
    {
        public ConditionnalActionRowDescription(string label, string actionName, Predicate<TModel> condition)
            : base(label, actionName)
        {
            _condition = condition;
        }

        private readonly Predicate<TModel> _condition;

        internal override string GetValue(HtmlHelper helper, TModel item, string formName, string field, int index)
        {
            if (_condition(item))
            {
                return base.GetValue(helper, item, formName, field, index);
            }
            return string.Empty;
        }
    }
}
